package com.wm.blog_admin.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.wm.blog_common.context.AdminBaseContextHandler;
import com.wm.blog_common.util.StringUtil;
import com.wm.blog_common.util.excel.FieldReflectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 *@ClassName MybatisUpdateInterceptor  mybatis更新操作,自动填充update_time和editor字段
 *@Author 半卷流年
 *@Date 2020/10/28 20:05
 */
@Component
@Slf4j
@Intercepts(@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}))
public class MybatisUpdateInterceptor implements Interceptor {

    private static final List<String> UPDATE_NAME_FIELD_NAME_LIST = Arrays.asList("editor","modifier");

    private static final List<String> UPDATE_TIME_FIELD_NAME_LIST = Arrays.asList("updateTime","modifyDate");

    private static final List<String> INSERT_TIME_FIELD_NAME_LIST = Arrays.asList("createTime","createDate");

    private static final List<String> INSERT_NAME_FIELD_NAME_LIST = Arrays.asList("creator");


    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        fillField(invocation);
        return invocation.proceed();
    }

    private void fillField(Invocation invocation) {
        SqlCommandType sqlCommandType = null;
        for (Object arg : invocation.getArgs()) {
            if(arg instanceof MappedStatement){
                MappedStatement mappedStatement = (MappedStatement) arg;
                sqlCommandType = mappedStatement.getSqlCommandType();
                log.info("请求更新/新增方法:{}",mappedStatement.getId());
                //如果是“增加”或“更新”操作，则继续进行默认操作信息赋值。否则，则退出
                if (sqlCommandType == SqlCommandType.INSERT || sqlCommandType == SqlCommandType.UPDATE) {
                    continue;
                } else {
                    break;
                }
            }
            boolean isInsert = sqlCommandType == SqlCommandType.INSERT;
            if(arg instanceof Map){
                Map<String,Object> map = (Map<String, Object>) arg;
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    Object value = entry.getValue();
                    if(Objects.nonNull(value)){
                        Field[] fields = FieldReflectionUtil.getAllFields(value.getClass());
                        if(!CollectionUtils.isEmpty(Arrays.asList(fields))){
                            Date nowTime = new Date();
                            String userName = AdminBaseContextHandler.getAdminUserName();
                            Long userId = AdminBaseContextHandler.getAdminUserId();
                            for (Field field : fields) {
                                if(Modifier.isAbstract(field.getModifiers()) || Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())){
                                    continue;
                                }
                                if (!field.isAccessible()){
                                    field.setAccessible(true);
                                }
                                String fieldName = field.getName();
                                if(isInsert){
                                    //新增
                                    if(INSERT_TIME_FIELD_NAME_LIST.contains(fieldName)){
                                        this.setFieldProperties(field,value,nowTime);
                                        log.info("填充属性成功:{},{}",fieldName,nowTime);
                                    }
                                    if(INSERT_NAME_FIELD_NAME_LIST.contains(fieldName)){
                                        this.setFieldProperties(field,value,userName);
                                        log.info("填充属性成功:{},{}",fieldName,userName);
                                    }
                                }else{
                                    //编辑
                                    if(UPDATE_TIME_FIELD_NAME_LIST.contains(fieldName)){
                                        this.setFieldProperties(field,value,nowTime);
                                        log.info("填充属性成功:{},{}",fieldName,nowTime);
                                    }
                                    if(UPDATE_NAME_FIELD_NAME_LIST.contains(fieldName)){
                                        this.setFieldProperties(field,value,userName);
                                        log.info("填充属性成功:{},{}",fieldName,userName);
                                    }
                                }
                        }
                    }
                        }
                    }
                }
            }
        }

    private void setFieldProperties(Field field,Object arg, Object data) {
        if(Objects.isNull(arg)){
            return;
        }
        try {
            field.set(arg,data);
        } catch (IllegalAccessException e) {
            log.error("反射填充对象属性异常:{},{}",field.getName(), JSONObject.toJSONString(data));
        }
    }

    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
